﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyAlbum.Model;
using MyAlbum.Data;
using MyAlbum.Utility;
using PersonalAlbum.Exceptions;
using MyAlbum.Logging;

namespace MyAlbum.Services
{
    public class EntryService : IEntryService
    {
        private IEntryRepository _repository;
        private IUser _user;
        private ILogger _logger;
        public EntryService(IEntryRepository entryRepository,
            IUser user,
            ILogger logger)
        {
            Assert.IsNotNull(entryRepository);
            this._repository = entryRepository;
            this._user = user;
            this._logger = logger;

        }
        public int CountItems()
        {
            return this._repository.CountItems(true);
        }
        public MyAlbum.Model.Entry GetLatestEntry()
        {
            bool visible = _user == null || _user.ShowOnlyVisibleEntries();
            return this._repository.GetLatestEntry(visible);
        }

        public List<Entry> GetEntriesByAlbum(string albumId)
        {
            return this.GetEntriesByAlbum(albumId, 1, int.MaxValue);
        }


        public List<Entry> GetItems()
        {
            return this.GetItems(1, int.MaxValue);
        }

        public List<Entry> GetItems(int pageNumber, int count)
        {
            bool visible = _user == null || _user.ShowOnlyVisibleEntries();
            /*TODO this is the bottle neck ->loading 100 entries 100ms with sql,450 entries 500ms, 1500 entries 2000ms
             * find who uses this service and force limit on entries count
             */
            return this._repository.GetItems(pageNumber > 0 ? pageNumber : 1, count, visible);
        }


        public void DeleteItem(Entry item)
        {
            if (item != null)
            {
                if (_user.AllowActions())
                {
                    this._repository.DeleteItem(item);
                }
                else
                {
                    _logger.Warning("An unauthorized attempt to delete entry (" + item.Id + ") by " + (_user == null ? " null user " : _user.Name));
                }
            }
            else
            {
                _logger.Warning("Attempt to delete null entry");
            }
        }

        public void UpdateItem(Entry item, IValidationSummary summary)
        {
            if (_user.AllowAdd())
            {
                Assert.IsNotNull(item);
                if (!FormsValidation.ContainsCharacters(item.Title))
                {
                    summary.AddError("Title", "Missing");
                }
                if (summary.IsValid)
                {
                    this._repository.UpdateItem(item);
                }
            }
            else
            {
                summary.AddError("Album", "Unauthorized");
                _logger.Warning("An unauthorized attempt to edit album (" + item.Id + ") by " + (_user == null ? " null user " : _user.Name));
            }
        }


        public Entry GetItemById(string entryId)
        {
            var entry = this._repository.GetEntryById(entryId, false);
            if (entry != null &&
                !entry.Visible &&
                _user.ShowOnlyVisibleEntries())
            {
                _logger.Warning("An attempt to view non visible entry (" + entryId + ") by " + (_user == null ? " null user " : _user.Name));
                entry = null;
            }
            return entry;
        }

        /// <summary>
        /// Load the latest entries
        /// </summary>
        /// <param name="count">The number of entries to load</param>
        /// <returns>List of Entry</returns>
        public List<MyAlbum.Model.Entry> GetLastItems(int count)
        {
            return this._repository.GetLatestEntries(count, true);
        }


        #region IEntryService Members


        public List<Entry> GetEntriesByAlbum(string albumId, int pageNumber, int count)
        {
            bool visible = _user == null || _user.ShowOnlyVisibleEntries();
            if (pageNumber <= 0)
            {
                pageNumber = 1;
            }
            return this._repository.GetEntriesByAlbum(albumId, pageNumber, count, visible);

        }

        public int GetEntriesCount(bool visible)
        {
            return this._repository.GetEntriesCount(visible);
        }

        public List<Entry> GetEntriesByTagName(string tagName)
        {
            bool visible = _user == null || _user.ShowOnlyVisibleEntries();
            return this._repository.GetEntriesByTagName(tagName, visible);
        }


        public List<MonthSummary> GetEntriesByMonthsSummary()
        {
            bool visible = _user == null || _user.ShowOnlyVisibleEntries();
            return this._repository.GetEntriesByMonthsSummary(visible);
        }

        /// <summary>
        /// Load random visible entries summary (no replies or tags)
        /// </summary>
        /// <param name="count">The max number of entries to load</param>
        /// <returns>List of Entry</returns>
        public List<MyAlbum.Model.Entry> LoadRandomEntriesSummary(int count)
        {
            return this._repository.LoadRandomEntriesSummary(count);
        }

        #endregion

        #region IDataService<Entry> Members


        public void AddItem(Entry item, IValidationSummary summary)
        {
            Assert.IsNotNull(item);
            if (_user.AllowAdd())
            {
                if (!FormsValidation.ContainsCharacters(item.Title))
                {
                    summary.AddError("Title", "Missing");
                }
                if (summary.IsValid)
                {
                    item.UserName = _user.Name;
                    item.Date = DateTime.UtcNow;
                    this._repository.AddItem(item);
                }
            }
            else
            {
                summary.AddError("Section", "Unauthorized");
                _logger.Warning("An unauthorized attempt to add entry  by " + (_user == null ? " null user " : _user.Name));
            }
        }

        #endregion
    }
}
